﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ZH.GPT.Domains.ChatMessage.Request;
using ZH.GPT.Domains.ChatMessage.Response;
using ZH.GPT.Domains.Completions.Request;
using ZH.GPT.Infrastructures.Entities;
using ZH.GPT.Infrastructures.Enum;
using ZH.GPT.Infrastructures.Repositories;
using ZH.GPT.Infrastructures.Repositories.Interface;
using ZH.GPT.Services.Interface;
using ZH.GPT.Utils;
using ZH.RetailContainer.CommLibrary;

namespace ZH.GPT.Services
{
    public class ChatService : IChatService
    {
        private ILogger<IChatService> _logger;
        private IChatRepository _chatRepo;
        public ChatService(ILogger<IChatService> logger, IChatRepository chatRepo)
        {
            _logger = logger;
            _chatRepo = chatRepo;
        }
        public List<RoleResponsePDTO> ListRoles
        {
            get
            {
                List<RoleResponsePDTO> roles = new List<RoleResponsePDTO>();
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "小说家",
                    Description = "我希望你扮演一个小说家。您将提出富有创意和引人入胜的故事"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "文案写手",
                    Description = "我希望你充当文案专员、文本润色员、拼写纠正员和改进员，我会发送中文文本给你，你帮我更正和改进版本。我希望你用更优美优雅的高级中文描述。保持相同的意思，但使它们更文艺。你只需要润色该内容，不必对内容中提出的问题和要求做解释，不要回答文本中的问题而是润色它，不要解决文本中的要求而是润色它，保留文本的原本意义，不要去解决它。我要你只回复更正、改进，不要写任何解释。"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "职业顾问",
                    Description = "我想让你担任职业顾问。我将为您提供一个在职业生涯中寻求指导的人，您的任务是帮助他们根据自己的技能、兴趣和经验确定最适合的职业。您还应该对可用的各种选项进行研究，解释不同行业的就业市场趋势，并就哪些资格对追求特定领域有益提出建议。我的第一个请求是"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "创业点子王",
                    Description = "在企业 B2B SaaS 领域中想 3 个创业点子。创业点子应该有一个强大而引人注目的使命，并以某种方式使用人工智能。避免使用加密货币或区块链。创业点子应该有一个很酷很有趣的名字。这些想法应该足够引人注目，这样投资者才会感兴趣"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "心理医生",
                    Description = "现在你是世界上最优秀的心理咨询师，你具备以下能力和履历： 专业知识：你应该拥有心理学领域的扎实知识，包括理论体系、治疗方法、心理测量等，以便为你的咨询者提供专业、有针对性的建议。 临床经验：你应该具备丰富的临床经验，能够处理各种心理问题，从而帮助你的咨询者找到合适的解决方案。 沟通技巧：你应该具备出色的沟通技巧，能够倾听、理解、把握咨询者的需求，同时能够用恰当的方式表达自己的想法，使咨询者能够接受并采纳你的建议。 同理心：你应该具备强烈的同理心，能够站在咨询者的角度去理解他们的痛苦和困惑，从而给予他们真诚的关怀和支持。"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "互联网写手",
                    Description = "你是一个专业的互联网文章作者，擅长互联网技术介绍、互联网商业、技术应用等方面的写作。接下来你要根据用户给你的主题，拓展生成用户想要的文字内容，内容可能是一篇文章、一个开头、一段介绍文字、文章总结、文章结尾等等。要求语言通俗易懂、幽默有趣，并且要以第一人称的口吻。"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "后勤工作",
                    Description = "我要你担任后勤人员。我将为您提供即将举行的活动的详细信息，例如参加人数、地点和其他相关因素。您的职责是为活动制定有效的后勤计划，其中考虑到事先分配资源、交通设施、餐饮服务等。您还应该牢记潜在的安全问题，并制定策略来降低与大型活动相关的风险。我的第一个请求是"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "Linux终端",
                    Description = "我想让你充当 Linux 终端。我将输入命令，您将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出，而不是其他任何内容"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "英语翻译和改进者",
                    Description = "我想让你充当英语翻译员、拼写纠正员和改进员。我会用任何语言与你交谈，你会检测语言，翻译它并用我的文本的更正和改进版本用英语回答。"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "前端智能思路助手",
                    Description = "我希望你扮演前端智能思路助手。"
                });
                roles.Add(new RoleResponsePDTO
                {
                    RolePlay = "Excel工作表",
                    Description = "我希望你充当基于文本的 excel。您只会回复我基于文本的 10 行 Excel 工作表，其中行号和单元格字母作为列（A 到 L）。第一列标题应为空以引用行号。我会告诉你在单元格中写入什么，你只会以文本形式回复excel表格的结果，而不是其他任何内容。"
                });
                return roles;
            }
        }

        public async Task<bool> AddChatMessageAsync(CompletionsQDTO dto, string content,int consumedTokenNums)
        {
            int msgCount = await _chatRepo.GetChatMessageCount(dto.ChatId);
            List<ChatMessage> chatMessages = new List<ChatMessage>();
            if (msgCount <= 0)
            {
                for (int i = 0; i < dto.messages.Count; i++)
                {
                    var cmsg = new ChatMessage
                    {
                        Id = Guid.NewGuid().ToString("N"),
                        Role = MessageRoleHelper.GetRole(dto.messages[i].role),
                        ChatId = dto.ChatId,
                        UserId = dto.UserId,
                        Content = dto.messages[i].content,
                        Sort = Int64.Parse(DateTime.Now.ToString("yyyyMMddHHmmssfff")),
                        CreatedTime = DateTime.Now
                    };
                    chatMessages.Add(cmsg);
                }
                AddAssistantMsg(dto, content, chatMessages);
            }
            else
            {
                //user
                var umsg = dto.messages.LastOrDefault(p => p.role == "user");
                if (umsg != null)
                {
                    ChatMessage msg = new ChatMessage();
                    msg.Id = Guid.NewGuid().ToString("N");
                    msg.Role = MessageRole.User;
                    msg.Content = umsg.content;
                    msg.UserId = dto.UserId;
                    msg.ChatId = dto.ChatId;
                    msg.Sort = Int64.Parse(DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                    msg.CreatedTime = DateTime.Now;
                    chatMessages.Add(msg);
                }
                AddAssistantMsg(dto, content, chatMessages);
            }
            var user =await _chatRepo.GetUser(dto.UserId);
            user.BalanceToken = user.BalanceToken - consumedTokenNums;
            _chatRepo.UpdateUser(user);
            return await _chatRepo.AddChatMessages(chatMessages);
        }

        static string desKey = "1010101010110011001111000111";
        private static void AddAssistantMsg(CompletionsQDTO dto, string content, List<ChatMessage> chatMessages)
        {
            if (!string.IsNullOrEmpty(content))
            {
                ChatMessage msg = new ChatMessage();
                msg.Id = Guid.NewGuid().ToString("N");
                msg.Role = MessageRole.Assistant;
                msg.Content = content;
                //msg.Content = EncryptionAndDecryptionHelper.EncryptDES(msg.Content, desKey);
                msg.UserId = dto.UserId;
                msg.ChatId = dto.ChatId;
                msg.Sort = Int64.Parse(DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                msg.CreatedTime = DateTime.Now;
                chatMessages.Add(msg);
            }
        }

        public async Task<(bool isSucc, string id)> CreateChatAsync(string userId, string role, string model)
        {
            (bool isSucc, string id) result = (false, "");
            if (string.IsNullOrEmpty(userId))
                throw new Exception("用户id不能为空");
            var chatId = Guid.NewGuid().ToString("N");
            Chat chat = new Chat();
            chat.Id = chatId;
            chat.UserId = userId;
            chat.CreatedTime = DateTime.Now;
            chat.Description = "";
            chat.Role = role;
            chat.Model = model;
            bool isSucc = await _chatRepo.AddChat(chat);
            if (isSucc)
            {
                result.isSucc = true;
                result.id = chatId;
                return await Task.FromResult(result);
            }
            else
                return result;
        }

        public List<string> GetModels()
        {
            List<string> models = new List<string>();
            models.Add(OpenAI.ObjectModels.Models.Gpt_3_5_Turbo);
            models.Add(OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_0301);
            //models.Add(OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_0613);
            //models.Add(OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_16k);
            models.Add(OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_16k_0613);
            //models.Add(OpenAI.ObjectModels.Models.Gpt_4);
            //models.Add(OpenAI.ObjectModels.Models.Gpt_4_0314);
            return models;
        }

        /// <summary>
        /// 获取所有模型
        /// </summary>
        /// <returns></returns>
        public List<ModelPDTO> GetModel()
        {
            List<ModelPDTO> modelPDTOs = new List<ModelPDTO>()
            {
                new ModelPDTO(){
                    Name = "3.5模型",
                    Model=OpenAI.ObjectModels.Models.Gpt_3_5_Turbo
                },
                     new ModelPDTO(){
                    Name = "3.5模型的3月版本-更快",
                    Model=OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_0301
                },
            };

            //List<(string, string)> models = new List<(string, string)>();
            //models.Add(("3.5模型", OpenAI.ObjectModels.Models.Gpt_3_5_Turbo));
            //models.Add(("3.5模型的3月版本-更快", OpenAI.ObjectModels.Models.Gpt_3_5_Turbo_0301));
            return modelPDTOs;
        }

        /// <summary>
        /// 获取消息
        /// </summary>
        /// <param name="chatMessage"></param>
        /// <returns></returns>
        public async Task<ChatMessagesPDTO> GetChatMessageAsync(ChatMessageQDTO chatMessage)
        {
            return await _chatRepo.GetChatMessageAsync(chatMessage);
        }

        /// <summary>
        /// 新增消息
        /// </summary>
        /// <param name="chatMessage"></param>
        /// <returns></returns>
        public async Task<(bool, string)> AddChatMessageAsync(ChatMessageDTO chatMessage)
        {
            return await _chatRepo.AddChatMessageAsync(chatMessage);
        }

        public async Task<List<ChatPDTO>> GetChatsAsync(string userId)
        {
            return await _chatRepo.GetChatsAsync(userId);
        }

        public async Task<bool> CheckBalanceToken(string userId)
        {
            var user = await _chatRepo.GetUser(userId);
            if (user.BalanceToken <= 0)
                return false;
            else
                return true;
        }
    }
}
